package org.fastiot.protocol

import grails.databinding.BindUsing
import org.fastiot.protocol.group.Groupable

/**
 * 基于字节码的通讯封包
 * Bytecode-based packet
 */
abstract class Packet {

    static enum Direction {
        Upstream(0), Downstream(1)
        final int value

        private Direction(int value) { this.value = value }

        static Direction byValue(int val) {
            values().find { it.value == val } ?:
                    { throw new IllegalArgumentException("Packet\$Direction ${val} not found") }()
        }
    }

    static enum Part {
        Header(0), Body(10), Checking(15)
        final int value

        private Part(int value) { this.value = value }

        static Part byValue(int val) {
            values().find { it.value == val } ?:
                    { throw new IllegalArgumentException("Packet\$Part ${val} not found") }()
        }
    }

    static class BodyGroupType {

        @BindUsing({ obj, source ->
            Groupable.Type.byValue(Integer.parseInt(source["request"] as String))
        })
        Groupable.Type request

        @BindUsing({ obj, source ->
            Groupable.Type.byValue(Integer.parseInt(source["response"] as String))
        })
        Groupable.Type response

        static constraints = {
            request(nullable: false, inList: Groupable.Type.values().toList())
            response(nullable: true, inList: Groupable.Type.values().toList())
        }
    }

    Integer code
    String hexCode
    String label
    /**
     * （发起）方向
     * 由终端发起，平台响应，即上行；由平台发起，终端响应，即下行。
     */
    @BindUsing({ obj, source ->
        Direction.byValue(Integer.parseInt(source["direction"] as String))
    })
    Direction direction

    /**
     * 正文编组类型
     * 当使用请求响应一体化的数据包定义时，支持请求和响应采用不同的正文编组结构。
     */
    BodyGroupType bodyGroupType

    boolean enabled = false
    String remark

    Date dateCreated
    Date lastUpdated

    static transients = ['hexCode']
    static embedded = ['bodyGroupType']

    static constraints = {
        code(min: 0, display: false)
        hexCode(blank: false, matches: /0-9a-fA-F/)
        label(blank: false)
        direction(nullable: false, inList: Direction.values().toList())
        bodyGroupType(nullable: false)
    }

    static mapping = {
        remark type: "text"
        tablePerHierarchy false
    }

    def beforeValidate() {
        if(hexCode && !code)
            code = Integer.parseInt(hexCode, 16)
    }

    def afterLoad() {
        if (code)
            hexCode = Integer.toHexString(code)
    }
}
